home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Frameworks / MacZoop 1.6.5 / Basic Classes / Z Sources / ZArray.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-09  |  14.2 KB  |  573 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            ObjectMacZapp        -- a standard Mac OOP application template
  5. *
  6. *
  7. *
  8. *            ZArray.cpp            -- the basic container class object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZArray.h"
  23. #include    "MacZoop.h"
  24.  
  25.  
  26. static short    vCompareFunc( void* a, void* b, const long ref);
  27.  
  28.  
  29. /*-------------------------------***  CONSTRUCTOR  ***----------------------------------*/
  30.  
  31.  
  32. ZArray::ZArray( short elementSize )
  33.     : ZComrade()
  34. {
  35.     blkSize = elementSize;
  36.     numElements = 0;
  37.     
  38.     FailNIL(a = NewHandle( 0 ));
  39. }
  40.  
  41. /*--------------------------------***  DESTRUCTOR  ***----------------------------------*/
  42.  
  43. ZArray::~ZArray()
  44. {
  45.     if (a)
  46.         DisposeHandle( a );
  47. }
  48.  
  49.  
  50. /*--------------------------------***  INSERTITEM  ***----------------------------------*/
  51. /*    
  52. Insert an item at position <index>
  53. ----------------------------------------------------------------------------------------*/
  54.  
  55. void    ZArray::InsertItem(void* item, const long index)
  56. {
  57.     // insert the item into the array at position <index>. The value of <index> is one-based.
  58.     // This extends the array by one item.
  59.     
  60.     InsertElement( index - 1 );
  61.     SetArrayItem( item, index );
  62.     
  63.     SendMessage( msgArrayItemInserted, (void*) index );
  64. }
  65.  
  66.  
  67. /*--------------------------------***  APPENDITEM  ***----------------------------------*/
  68. /*    
  69. add an item at the end of the array
  70. ----------------------------------------------------------------------------------------*/
  71.  
  72. void    ZArray::AppendItem(void* item)
  73. {
  74.     // adds the item to the end of the array. This grows it by one item.
  75.     
  76.     InsertElement( numElements );
  77.     SetArrayItem( item, numElements );
  78.     
  79.     SendMessage( msgArrayItemAdded, (void*) numElements );
  80. }
  81.  
  82.  
  83. /*-------------------------------***  SETARRAYITEM  ***---------------------------------*/
  84. /*    
  85. replace an item at position <index>
  86. ----------------------------------------------------------------------------------------*/
  87.  
  88. void    ZArray::SetArrayItem(void* item, const long index)
  89. {
  90.     // sets the item into the array at <index>, which is one-based.
  91.     
  92.     if ((index < 1) || (index > numElements))
  93.         FailOSErr( kIndexOutOfRangeErr );
  94.         
  95.     BlockMoveData(item, (*a + (blkSize * (index - 1))), blkSize);
  96.     
  97.     SendMessage( msgArrayItemChanged, (void*) index );
  98. }
  99.  
  100.  
  101. /*-------------------------------***  GETARRAYITEM  ***---------------------------------*/
  102. /*    
  103. return the item at position <index> (returns a COPY)
  104. ----------------------------------------------------------------------------------------*/
  105.  
  106. void    ZArray::GetArrayItem(void* item, const long index)
  107. {
  108.     // gets the item at poition <index> in the array. Index is one-based.
  109.     
  110.     if ((index < 1) || (index > numElements))
  111.         FailOSErr( kIndexOutOfRangeErr );
  112.         
  113.     BlockMoveData((*a + (blkSize * (index - 1))), item, blkSize);
  114. }
  115.  
  116.  
  117. /*---------------------------------***  FINDINDEX  ***----------------------------------*/
  118. /*
  119. returns the index of an item in the array, or 0 if not found.    
  120. ----------------------------------------------------------------------------------------*/
  121.  
  122. long    ZArray::FindIndex(void* item)
  123. {
  124.     // performs a linear search and returns the index of the item, if found.
  125.     
  126.     if ( numElements < 1 )
  127.         return 0;
  128.         
  129.     long        i = 0;
  130.     Boolean        found = FALSE;
  131.     
  132.     do
  133.     {
  134.         if (EqualMem(*a + ( blkSize * i ), item, blkSize))
  135.         {
  136.             found = TRUE;
  137.             break;
  138.         }
  139.     }
  140.     while( i++ < numElements );
  141.  
  142.     return ( found? i + 1 : 0 );
  143. }
  144.  
  145. /*--------------------------------***  DELETEITEM  ***----------------------------------*/
  146. /*    
  147. Delete an item at position <index>
  148. ----------------------------------------------------------------------------------------*/
  149.  
  150. void    ZArray::DeleteItem( const long index )
  151. {
  152.     // deletes the item at position <index> (1-based). Items above are moved down one.
  153.     
  154.     DeleteElement( index - 1 );
  155.     
  156.     SendMessage( msgArrayItemDeleted, (void*) index );
  157. }
  158.  
  159.  
  160. /*----------------------------------***  MOVEITEM  ***----------------------------------*/
  161. /*    
  162. move an item from one place in the array to another
  163. ----------------------------------------------------------------------------------------*/
  164.  
  165. void    ZArray::MoveItem( const long curIndex, const long newIndex )
  166. {
  167.     // moves the item at <curIndex> to position <newIndex> (all 1-based), moving other items
  168.     // as needed to keep things in order.
  169.     
  170.     if ((curIndex < 1) ||
  171.         (curIndex > numElements) ||
  172.         (newIndex < 1) ||
  173.         (newIndex > numElements))
  174.         FailOSErr( kIndexOutOfRangeErr );
  175.     
  176.     void* temp = (void*) NewPtr( blkSize );
  177.     
  178.     FailNIL(temp);
  179.     
  180.     // copy the item we want to move to a temporary space
  181.     
  182.     GetArrayItem( temp, curIndex);
  183.     
  184.     // delete its current position, which will move stuff as needed
  185.     
  186.     DeleteElement( curIndex - 1 );
  187.     
  188.     // insert it into the new position, which moves other stuff as needed
  189.     
  190.     InsertItem( temp, newIndex );
  191.     
  192.     // get rid of the temporary space
  193.     
  194.     DisposePtr((Ptr) temp);
  195.     SendMessage( msgArrayItemMoved, (void*) newIndex );
  196. }
  197.  
  198.  
  199. /*----------------------------------***  SWAPITEM  ***----------------------------------*/
  200. /*    
  201. Swap two items in the array
  202. ----------------------------------------------------------------------------------------*/
  203.  
  204. void    ZArray::Swap( const long itema, const long itemb )
  205. {
  206.     // swaps items a and b.
  207.     if ((itema < 1) ||
  208.         (itema > numElements) ||
  209.         (itemb < 1) ||
  210.         (itemb > numElements))
  211.         FailOSErr( kIndexOutOfRangeErr );
  212.     
  213.     // make some swap space
  214.     
  215.     void* tempa = (void*) NewPtr( blkSize );
  216.     void* tempb = (void*) NewPtr( blkSize );
  217.     FailNIL(tempa);
  218.     FailNIL(tempb);
  219.     
  220.     GetArrayItem( tempa, itema);
  221.     GetArrayItem( tempb, itemb);
  222.     SetArrayItem( tempa, itemb);
  223.     SetArrayItem( tempb, itema);
  224.     
  225.     DisposePtr((Ptr) tempa);
  226.     DisposePtr((Ptr) tempb);
  227.     
  228.     SendMessage( msgArrayItemMoved, (void*) itema );
  229. }
  230.  
  231.  
  232. /*---------------------------------***  COUNTITEMS  ***---------------------------------*/
  233. /*    
  234. return the number of items in the array
  235. ----------------------------------------------------------------------------------------*/
  236.  
  237. long    ZArray::CountItems()
  238. {
  239.     return numElements;
  240. }
  241.  
  242.  
  243. /*----------------------------------***  DOFOREACH  ***---------------------------------*/
  244. /*    
  245. for each item in the array, pass it to the grovelling proc passed
  246. ----------------------------------------------------------------------------------------*/
  247.  
  248. void    ZArray::DoForEach(IteratorProcPtr aProc, const long ref)
  249. {
  250.     if (aProc && (numElements > 0))
  251.     {
  252.         long    i = numElements;
  253.         void*    temp = (void*) NewPtr( blkSize );
  254.         
  255.         FailNIL( temp );
  256.         
  257.         while ( i )
  258.         {
  259.             GetArrayItem( temp, i);
  260.             (*aProc)(temp, ref);
  261.             
  262.             // in case the proc changed the item, set it back
  263.             
  264.             SetArrayItem( temp, i--);
  265.         }
  266.         
  267.         DisposePtr((Ptr) temp);
  268.     }
  269. }
  270.  
  271.  
  272. /*-------------------------------------***  SORT  ***-----------------------------------*/
  273. /*    
  274. sort the items in the array into order. The supplied comparison function allows you to
  275. sort anything based on any ordering criteria. Uses a very fast shellsort algorithm. Your
  276. sort function needs to examine the relevant criteria in the items passed, and decide what
  277. order they come in. It should return -1 if a < b, +1 if a > b, and 0 if equal. <ref> can be
  278. anything you want- it is simply passed to the compare function. It might be another object
  279. for example (hint, hint!).
  280.  
  281. ----------------------------------------------------------------------------------------*/
  282.  
  283. void    ZArray::Sort( register SortCmpProcPtr compareProc, register const long ref )
  284. {
  285.     register long    E,N,M,J,K,R;
  286.     register short    comp;
  287.     
  288.     register void*    itema;
  289.     register void*    itemb;
  290.     
  291.     // sanity check- there IS a sort function, right?
  292.     
  293.     FailOSErr((compareProc == NULL)? paramErr : noErr );
  294.     
  295.     // allocate some temporary storage
  296.     
  297.     FailNIL(itema = (void*) NewPtr( blkSize ));
  298.     FailNIL(itemb = (void*) NewPtr( blkSize ));
  299.     
  300.     // initialise the control variables to the number of elements in the list
  301.     
  302.     M = E = N = numElements;
  303.     N++;
  304.     
  305.     // and... sort!
  306.     
  307.     do
  308.     {
  309.         M /= 2;
  310.         if (M <= 0)
  311.             break;
  312.             
  313.         K = E - M;
  314.         J = 1;
  315.         
  316.         do
  317.         {
  318.             N = J;
  319.             do
  320.             {
  321.                 R = N + M;
  322.                 GetArrayItem( itema, N );                        // get first item
  323.                 GetArrayItem( itemb, R );                        // get second item
  324.                 
  325.                 comp = (*compareProc)( itema, itemb, ref );        // call the comparison function
  326.                 
  327.                 if (comp < 1)                                    // no need to swap (a <= b)
  328.                     break;
  329.                     
  330.                 Swap( N, R );                                    // swap items in the array
  331.                     
  332.                 N -= M;
  333.             }
  334.             while ( N > 0 );
  335.             J++;
  336.         }
  337.         while (J <= K);
  338.     }
  339.     while( M > 0 );
  340.     
  341.     // all done, now release the temporary storage
  342.     
  343.     DisposePtr((Ptr) itema);
  344.     DisposePtr((Ptr) itemb);
  345. }
  346.  
  347. /*-------------------------------------***  SORT  ***-----------------------------------*/
  348. /*    
  349. simpler interface to Sort- indirectly calls the Compare method, which you can override.
  350.  
  351. ----------------------------------------------------------------------------------------*/
  352.  
  353. void    ZArray::Sort()
  354. {
  355.     Sort( vCompareFunc, (long) this );
  356. }
  357.  
  358. /*----------------------------------***  COMPARE  ***-----------------------------------*/
  359. /*
  360. compare two items and return their relative ordering: -1 if a < b, +1 if a > b, 0 if a == b.
  361. You need to override this if you wish to use the simple call to Sort() above.    
  362. ----------------------------------------------------------------------------------------*/
  363.  
  364. short    ZArray::Compare( void* itema, void* itemb, const long ref )
  365. {
  366.     return 0;
  367. }
  368.  
  369. /*------------------------------***  INSERTSORTEDITEM  ***------------------------------*/
  370. /*
  371. insert the item into the list at the correct place assuming the list is sorted. This
  372. does a binary search to locate the position, based on the comparison function provided.
  373. Normally the comparison function is the same one you'd use with sort, so everything
  374. agrees. Returns the index poistion it was inserted at.
  375. ----------------------------------------------------------------------------------------*/
  376.  
  377. long    ZArray::InsertSortedItem( void* item, SortCmpProcPtr compareProc, const long ref )
  378. {
  379.     long    pos = BFindIndex( item, compareProc, ref );
  380.     
  381.     if ( pos > 0 )
  382.         InsertItem( item, pos );
  383.         
  384.     return pos;
  385. }
  386.  
  387. /*------------------------------***  INSERTSORTEDITEM  ***------------------------------*/
  388. /*
  389. insert the item into the list at the correct place assuming the list is sorted. This uses
  390. the built in compare function which calls the Compare method.
  391. ----------------------------------------------------------------------------------------*/
  392.  
  393. long    ZArray::InsertSortedItem( void* item, const long ref )
  394. {
  395.     return InsertSortedItem( item, vCompareFunc, ref );
  396. }
  397.  
  398.  
  399. /*-----------------------------***  Protected Members  ***------------------------------*/
  400.  
  401.  
  402. /*-------------------------------***  INSERTELEMENT  ***--------------------------------*/
  403. /*    
  404. make space for one element in the handle
  405. ----------------------------------------------------------------------------------------*/
  406.  
  407. void    ZArray::InsertElement( const long index )
  408. {
  409.     // grow the handle by one element, moving items above <index> up one. This also
  410.     // sets the numElements data member. Index is zero-based.
  411.     
  412.     long    newSize;
  413.     
  414.     // check that the index parameter is sensible
  415.     
  416.     if (index < 0 || index > numElements)
  417.         FailOSErr( kIndexOutOfRangeErr );
  418.     
  419.     // grow the handle
  420.     
  421.     newSize = GetHandleSize( a ) + blkSize;
  422.     SetHandleSize(a, newSize);
  423.     
  424.     FailOSErr(MemError());
  425.     
  426.     // OK, the handle is now larger by one element- do we need to move any data around?
  427.     
  428.     if (index < numElements)
  429.     {
  430.         // yes, subsequent entries move up by <blkSize> bytes
  431.         
  432.         HLock( a );
  433.         BlockMoveData(    *a + (blkSize * index),
  434.                         *a + (blkSize * (index + 1)),
  435.                         blkSize * (numElements - index));
  436.         HUnlock( a );
  437.     }
  438.     
  439.     // increment the count of elements
  440.     
  441.     numElements++;
  442. }
  443.  
  444. /*-------------------------------***  DELETEELEMENT  ***--------------------------------*/
  445. /*    
  446. remove space for one element in the handle
  447. ----------------------------------------------------------------------------------------*/
  448.  
  449. void    ZArray::DeleteElement( const long index )
  450. {
  451.     // shrink the handle by one element, after moving entries above <index> down by one.
  452.     // <index> is zero-based.
  453.     
  454.     // check that the index parameter is sensible
  455.     
  456.     if (index < 0 || index > numElements)
  457.         FailOSErr( kIndexOutOfRangeErr );
  458.         
  459.     // one less element
  460.     
  461.     numElements--;
  462.         
  463.     // if the index is not the last item, move everything down to fill the space
  464.     
  465.     if (index < numElements)
  466.     {
  467.         HLock( a );
  468.         BlockMoveData(    *a + (blkSize * (index + 1)),
  469.                         *a + (blkSize * index),
  470.                         blkSize * (numElements - index + 1));
  471.         HUnlock( a );
  472.     }
  473.     
  474.     // shrink the handle
  475.     
  476.     SetHandleSize(a, blkSize * numElements);
  477. }
  478.  
  479.  
  480. /*--------------------------------***  BINARYSEARCH  ***--------------------------------*/
  481. /*    
  482. use the compare function to determine where the item SHOULD be inserted
  483. ----------------------------------------------------------------------------------------*/
  484.  
  485. long    ZArray::BFindIndex( void* item, SortCmpProcPtr compareProc, const long ref )
  486. {
  487.     unsigned long    lowItem, highItem, midItem;
  488.     short            compare;
  489.     void*            itemB;
  490.     long            pos = 1;
  491.     
  492.     FailNILParam( compareProc );
  493.     
  494.     lowItem = 0;
  495.     highItem = numElements + 1;
  496.     
  497.     // if the list is empty, we return item 1, since we can simply append the item.
  498.     
  499.     if ( numElements < 1 )
  500.         pos = 1;
  501.     else
  502.     {
  503.         // make space for the item we are going to compare
  504.         
  505.         FailNIL( itemB = (void*) NewPtr( blkSize ));
  506.         
  507.         while (( highItem - lowItem ) > 1 )
  508.         {
  509.             midItem = ( highItem + lowItem ) >> 1;
  510.             
  511.             GetArrayItem( itemB, midItem );
  512.             
  513.             // compare this item to the one we are looking for
  514.             
  515.             compare = (*compareProc)( item, itemB, ref );
  516.             
  517.             if ( compare > 0 )
  518.                 lowItem = midItem;
  519.             else
  520.                 highItem = midItem;
  521.         }
  522.         
  523.         DisposePtr((Ptr) itemB );
  524.         pos = MAX( midItem, 1 );
  525.     }
  526.     
  527.     return pos;
  528. }
  529.  
  530.  
  531. #pragma mark -
  532. /*--------------------------------***  vCompareFunc  ***--------------------------------*/
  533.  
  534. static short    vCompareFunc( void* a, void* b, const long ref)
  535. {
  536.     ZArray*        theArray = (ZArray*) ref;
  537.     
  538.     if ( theArray )
  539.         return theArray->Compare( a, b, ref );    
  540.     else
  541.         return 0;
  542. }
  543.  
  544.  
  545. /*----------------------------------***  EQUALMEM  ***----------------------------------*/
  546. /*    
  547. compare two blocks of memory and return TRUE if they are equal
  548. ----------------------------------------------------------------------------------------*/
  549.  
  550. Boolean        EqualMem( void* a, void* b, const unsigned long length )
  551. {
  552.     Boolean        result = (length > 0);
  553.     Ptr            aa, bb;
  554.     
  555.     register unsigned long    len = length;
  556.     
  557.     aa = (Ptr) a;
  558.     bb = (Ptr) b;
  559.     
  560.     while( len-- )
  561.     {
  562.         if ( *aa++ != *bb++ )
  563.         {
  564.             result = FALSE;
  565.             break;
  566.         }
  567.     }
  568.  
  569.     return result;
  570. }
  571.  
  572.  
  573.